package tr.mesir.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.jboss.envers.VersionsReader;
import org.jboss.envers.VersionsReaderFactory;
import org.jboss.envers.query.VersionsRestrictions;
import org.springframework.stereotype.Repository;

import tr.mesir.domain.AddressBook;

/**
 * @Repository annotation indicates that this is a DAO. EntityManager is injected 
 * automatically according to the @PersistenceContext annotation. The class does the
 * simple CRUD and hibernate search stuff on AddressBook pojo.
 * 
 * @author mertcaliskan
 */
@Repository
public class AddressBookDAOImpl implements AddressBookDAO {

	@PersistenceContext
	protected EntityManager entityManager;

	public AddressBook loadById(Long id) {
		return entityManager.find(AddressBook.class, id);
	}

	public void save(AddressBook addressBook) {
		entityManager.persist(addressBook);
	}

	/*
	 * Hibernate search indexes should also be updated after doing an update on the persistent object.
	 */
	public void update(AddressBook addressBook) {
		entityManager.merge(addressBook);
		getFullTextEntityManager().index(addressBook);
	}

	public void delete(AddressBook addressBook) {
		entityManager.remove(addressBook);
	}

	@SuppressWarnings("unchecked")
	public List<AddressBook> loadAll() {
		return entityManager.createQuery("from AddressBook").getResultList();
	}

	/* This is the envers query that gets the revisions of a specified entity (by a given id)
	 * for detail use of forRevisionsOfEntity method see ContactDAOImpl#getContactVersions()
	 */
	@SuppressWarnings("unchecked")
	public List<AddressBook> getAddressBookVersions(Long id) {
		VersionsReader reader = VersionsReaderFactory.get(entityManager);
		List<AddressBook> revisions = reader.createQuery().forRevisionsOfEntity(AddressBook.class, true, true).add(
						VersionsRestrictions.idEq(id)).getResultList();
		
		return revisions;
	}

	@SuppressWarnings("unchecked")
	public List<String> findAllTitles() {
		return entityManager.createQuery("select ab.title from AddressBook ab")
				.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<AddressBook> findByWord(String searchWord)
			throws ParseException {

		// Since contacts list is declared as @IndexedEmbedded inside AddressBook,
		// we can search through the name or email of a contact also.
		MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[] {
				"title", "contacts.name", "contacts.email" },
				new StandardAnalyzer());
		Query query = parser.parse(searchWord);

		FullTextQuery ftq = getFullTextEntityManager().createFullTextQuery(
				query, AddressBook.class);
		return ftq.getResultList();
	}

	/* Getting the entity manager for the full-text operations
	 */
	private FullTextEntityManager getFullTextEntityManager() {
		FullTextEntityManager fullTextEntityManager = Search
				.getFullTextEntityManager(entityManager);
		return fullTextEntityManager;
	}
}